namespace WP7Contrib.Services.BingMaps.Model
{
    using System;
    using System.Globalization;
    using Microsoft.Phone.Controls.Maps;
    using Common;

    public class SearchCriterion : BaseModel, ICriterion<SearchCriterion>,
                                              IEquatable<SearchCriterion>,
                                              ICloneable<SearchCriterion>,
                                              ISearchCriterion
    {
        private CultureInfo culture;
        private string query;
        private LocationRect boundingRectangle;
        private SourceType source;
        private int radius;
        private int resultSize;

        public SearchCriterion()
        {
            this.Reset();
        }

        public CultureInfo Culture
        {
            get
            {
                return this.culture;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.culture, value, () => this.Culture);
            }
        }

        public string Query
        {
            get
            {
                return this.query;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.query, value, () => this.Query);
            }
        }

        public LocationRect BoundingRectangle
        {
            get
            {
                return this.boundingRectangle;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.boundingRectangle, value, () => this.BoundingRectangle);
            }
        }

        public int Radius
        {
            get
            {
                return this.radius;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.radius, value, () => this.Radius);
            }
        }

        public int ResultSize
        {
            get
            {
                return this.resultSize;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.resultSize, value, () => this.ResultSize);
            }
        }

        public SourceType Source
        {
            get
            {
                return this.source;
            }
            set
            {
                this.SetPropertyAndNotify(ref this.source, value, () => this.Source);
            }
        }

        public bool HasBoundingRectangle
        {
            get { return this.BoundingRectangle != null; }
        }

        public bool HasCulture
        {
            get { return this.Culture != null; }
        }

        public SearchCriterion Reset()
        {
            this.culture = CultureInfo.CurrentCulture;
            this.query = null;
            this.boundingRectangle = new LocationRect();
            this.Radius = 5;
            this.ResultSize = 50;
            this.Source = SourceType.Phonebook;

            return this;
        }

          public static bool operator ==(SearchCriterion sc1, SearchCriterion sc2)
        {
            return Equals(sc1, sc2);
        }

        public static bool operator !=(SearchCriterion sc1, SearchCriterion sc2)
        {
            return !Equals(sc1, sc2);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }

            return obj is SearchCriterion && this.Equals((SearchCriterion)obj);
        }

        public bool Equals(SearchCriterion other)
        {
            if (ReferenceEquals(null, other))
            {
                return false;
            }

            if (!object.Equals(this.Culture, other.Culture))
            {
                return false;
            }

            if (this.Query != other.Query)
            {
                return false;
            }

            if (!object.Equals(this.BoundingRectangle, other.BoundingRectangle))
            {
                return false;
            }

            if (this.Radius != other.Radius)
            {
                return false;
            }

            if (this.ResultSize != other.ResultSize)
            {
                return false;
            }

            if (this.Source != other.Source)
            {
                return false;
            }

            return true;
        }

        public override int GetHashCode()
        {
            return this.CombineHashCodes(this.Culture, this.Query, this.BoundingRectangle, this.ResultSize, this.Radius, this.Source);
        }

        ISearchCriterion ICloneable<ISearchCriterion>.ShallowClone()
        {
            return this.ShallowClone();
        }

        public SearchCriterion ShallowClone()
        {
            var criterion = new SearchCriterion
            {
                Culture = this.Culture,
                Query = this.Query,
                BoundingRectangle = this.BoundingRectangle,
                ResultSize = ResultSize,
                Radius = Radius,
                Source = Source
            };

            return criterion;
        }

        ISearchCriterion ICloneable<ISearchCriterion>.DeepClone()
        {
            return this.DeepClone();
        }

        public SearchCriterion DeepClone()
        {
            var criterion = new SearchCriterion
            {
                Query = this.Query,
                ResultSize = this.ResultSize,
                Radius = this.Radius,
                Source = this.Source
            };

            if (this.HasCulture)
                criterion.Culture = new CultureInfo(this.Culture.Name);

            if (this.HasBoundingRectangle)
                criterion.BoundingRectangle = new LocationRect(this.BoundingRectangle);

            return criterion;
        }
    }
}